import type { Ref } from "vue";
import { getMessageBySessionID } from "@/Dexie/MessageDB";
import { getUserInfoFromDB } from "@/Dexie/UserDB";
import { selectedTypeFunc, sessionIdSelectedFunc } from "@/views/ChatView/Hooks";
import { sendSocketMsg } from "@/websocket/socket-io";
import { calcListTotal, findIndexByBinary, getNow } from "@/utils/utils";
import { emitterEmit, emitterOff, emitterOn } from "@/mitt/mitt";
import { getVirtualHeight } from "@/components/ChatBox/ChatContent/ChatMsgItem/Hooks";
// 聊天显示的消息数据
const chatMessageList: Ref<msgTableItemType[]> = ref([]);
// 消息距离顶部的margin
const msgTopMargin: Ref<number> = ref(0);
// 消息距离底部的margin
const msgBottomMargin: Ref<number> = ref(0);
// 判断是否在底部
let isBottom: Ref<boolean> = ref(true);
// sessionID聊天内容的高度数组
const sessionVirtualHeight: { [key: string]: number[] } = {};
// calculateVirtualHeight缓存 key为`${session_id}-${sender}-${timestamp}`
const msgHeight: { [key: string]: number } = {};
// 列表显示的数量
const maxShowNumber: number = 15;
// 新消息数量
const newMessageLengthObj: Ref<{ [key: string]: number }> = ref({});

export const isBottomFunc = (): [(() => Ref<boolean>), ((value: boolean) => void)] => {
  const get = () => {
    return isBottom;
  };
  const set = (value: boolean) => {
    isBottom.value = value;
  };
  return [get, set];
};
/**
 * 新消息数量对象的get/set
 */
export const newMessageLengthFunc = (): [(() => Ref<{ [p: string]: number }>), ((sessionId: string, value: number) => void), (() => void)] => {
  const get = () => {
    return newMessageLengthObj;
  };
  const set = (sessionId: string, value: number) => {
    newMessageLengthObj.value[sessionId] = value;
    localStorage["newMessageLengthObj"] = JSON.stringify(newMessageLengthObj.value);
  };
  const init = () => {
    if (localStorage["newMessageLengthObj"]) {
      newMessageLengthObj.value = JSON.parse(localStorage["newMessageLengthObj"]);
    }
  };
  return [get, set, init];
};

// 获取和设置消息列表的 marginTop 和 marginBottom
export const msgMarginFunc = (): [() => Ref<string>[], (top: number, bottom: number) => void] => {
  const msgTopMarginPx: Ref<string> = ref("");
  const msgBottomMarginPx: Ref<string> = ref("");
  watch(msgTopMargin, () => {
    msgTopMarginPx.value = msgTopMargin.value + "px";
  });
  watch(msgBottomMargin, () => {
    msgBottomMarginPx.value = msgBottomMargin.value + "px";
  });
  const get = () => {
    return [msgTopMarginPx, msgBottomMarginPx];
  };
  const set = (top: number, bottom: number) => {
    if (top !== undefined && top !== null) {
      msgTopMargin.value = top;
    }
    if (bottom !== undefined && bottom !== null) {
      msgBottomMargin.value = bottom;
    }
  };
  return [get, set];
};
// 获取和设置聊天消息列表
export const chatMessageListFunc = (): [(() => Ref<msgTableItemType[]>), ((list: msgTableItemType[]) => void)] => {
  const get = () => {
    return chatMessageList;
  };
  const set = (list: msgTableItemType[]) => {
    chatMessageList.value = list;
  };
  return [get, set];
};
// 控制加载消息时显示loading
export const loadingFunc = (): [Ref<boolean>, ((result: boolean) => void)] => {
  const showLoading: Ref<boolean> = ref(true);
  const updateLoading = (result: boolean) => {
    showLoading.value = result;
  };
  return [showLoading, updateLoading];
};
/**
 * 监听session_id变化，然后更新消息和loading
 * @param sessionId 会话 ID
 * @param updateLoading
 * @param callback
 */
export const sessionIdChangedWatcher = (sessionId: Ref<string>, updateLoading: (result: boolean) => void, callback: any) => {
  watch(sessionId, async (newValue, oldValue) => {
    updateLoading(true);
    // 获取新的信息
    const [mt, mb, chatList] = await getChatMessageList(sessionId.value);
    msgTopMargin.value = mt;
    msgBottomMargin.value = mb;
    chatMessageList.value = chatList;
    await nextTick();
    callback();
    updateLoading(false);
    newMessageLengthFunc()[1](sessionId.value, 0);
    // 更新监听对象
    emitterOff(`chatMessage-${oldValue}`);
    emitterOn(`chatMessage-${newValue}`, async (data: [number, boolean, boolean]) => {
      let [topHeight, refresh, isMe] = data;
      // 新数据进来且不在底部且不是自己的数据 的时候就不进行任何操作了，后续滚动会进行新的操作 进行新消息+1即可
      if (refresh && !isBottom.value && !isMe) {
        newMessageLengthFunc()[1](sessionId.value, (newMessageLengthObj.value[sessionId.value] || 0) + 1);
        return;
      }
      console.log(isBottom.value);
      // 在底部就直接将新数据的数量清0
      if (isBottom.value) {
        newMessageLengthFunc()[1](sessionId.value, 0);
      }
      const [mt, mb, chatList] = await getChatMessageList(sessionId.value, topHeight, refresh);
      msgTopMargin.value = mt;
      msgBottomMargin.value = mb;
      chatMessageList.value = chatList;
      // 是我发送的消息就直接滑倒最底部
      if (isMe) {
        await nextTick();
        emitterEmit("scrollEnd");
        return;
      }
      // 新数据且在底部我需要通知滑到底部
      if (refresh) {
        await nextTick();
        emitterEmit("scrollEnd");
      }
    });
  });
};

/**
 * 计算消息列表的虚拟高度
 * @param messageList 消息列表
 * @returns 虚拟高度列表
 */
const calculateVirtualHeight = (messageList: msgTableItemType[]): number[] => {
  let heightList: number[] = [];
  messageList.forEach((item, index) => {
    if (msgHeight[`${item.session_id}-${item.sender}-${item.timestamp}`]) {
      heightList.push(msgHeight[`${item.session_id}-${item.sender}-${item.timestamp}`]);
      return;
    }
    let height = getVirtualHeight(item);
    heightList.push(height);
    msgHeight[`${item.session_id}-${item.sender}-${item.timestamp}`] = height;
  });
  return heightList;
};

/**
 * 计算消息列表的 marginTop 和 marginBottom
 * @param heightList 虚拟高度列表
 * @param topHeight 顶部高度
 * @param result 消息列表
 * @returns [marginTop, marginBottom, result]
 */
const calculateMargin = (heightList: number[], topHeight: number, result: msgTableItemType[]): [number, number, msgTableItemType[]] => {
  let marginTop = 0;
  let marginBottom = 0;
  if (heightList.length < maxShowNumber) {
    return [marginTop, marginBottom, result];
  }
  // 二分法求展示的第一个index
  let index = findIndexByBinary(heightList, topHeight);
  if (index === -1) {
    marginTop = calcListTotal(heightList.slice(0, (heightList.length - maxShowNumber)));
    marginBottom = 0;
    result = result.slice(-maxShowNumber);
    return [marginTop, marginBottom, result];
  }
  marginTop = calcListTotal(heightList.slice(0, index));
  // 底部
  if ((heightList.length - maxShowNumber) < (index)) {
    marginTop = calcListTotal(heightList.slice(0, (heightList.length - maxShowNumber)));
    marginBottom = 0;
    result = result.slice(-maxShowNumber);
  } else {
    // 非底部
    let mbList = heightList.slice(index + maxShowNumber);
    marginBottom = mbList.length ? calcListTotal(mbList) : 0;
    result = result.slice(index, index + maxShowNumber);
  }
  return [marginTop, marginBottom, result];
};
/**
 * 获取聊天消息列表
 * @param sessionId 会话 ID
 * @param topHeight 顶部高度
 * @param refresh 是否刷新
 * @returns [marginTop, marginBottom, result]
 */
const getChatMessageList = async (sessionId: string, topHeight?: number, refresh?: boolean): Promise<[number, number, msgTableItemType[]]> => {
  let result = await getMessageBySessionID(sessionId);
  // 切换到新的聊天对象 需要重新获取数据
  if (topHeight === undefined && !refresh) {
    let marginTop: number = 0;
    let heightList: number[] = calculateVirtualHeight(result);
    // 缓存会话的虚拟高度列表
    sessionVirtualHeight[sessionId] = heightList;
    // 计算超出maxShowNumber个数据的高度用作 marginTop
    if (result.length > maxShowNumber) {
      let more = result.length - maxShowNumber;
      for (let i = 0; i < more; i++) {
        marginTop += heightList[i];
      }
      result = result.slice(-maxShowNumber);
    }
    return [marginTop, 0, result];
  }
  let heightList: number[] = [];
  // 滚动条滚动上下滑动查看聊天记录
  if (!refresh) {
    return calculateMargin(sessionVirtualHeight[sessionId], topHeight || 0, result);
  }
  // 新数据加入或者删除等操作重新计算数据 在底部的时候
  heightList = calculateVirtualHeight(result);
  // 缓存会话的虚拟高度列表
  sessionVirtualHeight[sessionId] = heightList;
  return calculateMargin(sessionVirtualHeight[sessionId], Infinity, result);
};
// 获取用户信息并判断是否是自己
export const initUserInfo = async (sender: string, senderInfo: Ref<userInfoType | undefined>, isMe: Ref<boolean>) => {
  let userInfo = await getUserInfoFromDB(sender);
  if (userInfo) {
    senderInfo.value = userInfo;
  }
  if (sender === localStorage["account"]) {
    isMe.value = true;
  }
};
// 发送聊天消息
export const sendMessage = (msg: string): void => {
  // 获取session_id
  const [getSessionId] = sessionIdSelectedFunc();
  const session_id = getSessionId();
  if (session_id.value === "") {
    ElMessage.error("请先选择发送对象！");
    return;
  }
  // 初始化发送对象
  const [getSelectedType] = selectedTypeFunc();
  let type = getSelectedType().value;
  let msgTo: msgToType = { sender: "", sessionID: "", type };
  msgTo.sessionID = session_id.value;
  msgTo.sender = localStorage["account"];
  // 发送消息
  sendSocketMsg("message", {
    ...msgTo,
    message: msg,
    timestamp: getNow()
  });
};
